package com.s7.app.mvp;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 泛型转实体对象工具
 */
public class GenericsUtils {

    /**
     * 通过反射, 获取泛型实体
     * 内部获取第X个类型参数的真实类型 ，反射new出对象
     * @param o
     * @param i
     * @param <T>
     * @return
     */
    public static <T> T getT(Object o, int i) {
        try {
            return ((Class<T>) ((ParameterizedType) (o.getClass().getGenericSuperclass()))
                    .getActualTypeArguments()[i]).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
//            throw new RuntimeException("泛型不能为空");
        }
        return null;
    }

    /**
     * 获取泛型实体
     * 内部获取第0个类型参数的真实类型 ，反射new出对象
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getT(Class clazz) {
        return getT(clazz, 0);
    }

    /**
     * 获取泛型实体
     * 内部获取第X个类型参数的真实类型 ，反射new出对象
     * @param clazz
     * @param index
     * @param <T>
     * @return
     */
    public static <T> T getT(Class clazz, int index) {
        Class<T> entityClass = getSuperClassGenricType(clazz, index);
        if (entityClass == null) {
            return null;
        }
        if (entityClass instanceof Object) {
            return null;
        } else {
            try {
                return entityClass.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    /**
     * 通过反射,获得定义Class时声明的父类的范型参数的类型.
     *   如 MainActivity extends BaseMActivity<BasePresenter>
     * @param clazz clazz 需要反射的类,该类必须继承范型父类
     * @return 范型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，所以直接返回
     */
    public static Class getSuperClassGenricType(Class clazz) {
        return getSuperClassGenricType(clazz, 0);
    }

    /**
     * 通过反射,获得定义Class时声明的父类的范型参数的类型.
     *  如 MainActivity extends BaseMActivity<BasePresenter>
     * @param clazz 需要反射的类,该类必须继承范型父类
     * @param index 泛型参数所在索引,从0开始.
     * @return 范型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，所以直接返回
     */
    public static Class getSuperClassGenricType(Class clazz, int index) throws IndexOutOfBoundsException {

        Type genType = clazz.getGenericSuperclass();

        /**
         * 如果没有实现ParameterizedType接口，即不支持泛型
         * 直接返回Object.class
         */
        if (!(genType instanceof ParameterizedType)) {
            return Object.class;
        }

        /**
         * 返回表示此类型实际类型参数的Type对象的数组,数组里放的都是对应类型的Class,
         *   如:MainActivity extends BaseMActivity<BasePresenter> 就返回BasePresenter类型
         */
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        /**
         * 如果索引 index 不在 Type对象的数组 范围内
         * 直接返回Object.class
         */
        if (index >= params.length || index < 0) {
            return Object.class;
        }

        /**
         * 如果 泛型的类型不是Class
         * 直接返回Object.class
         */
        if (!(params[index] instanceof Class)) {
            return Object.class;
        }

        return (Class) params[index];
    }

}
